﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;
using Microsoft.EntityFrameworkCore;
using Eqwww.Data;
using Eqwww.Domain.Models.SystemManage;
using Eqwww.Code;
using Eqwww.Domain;
using Microsoft.AspNetCore.Identity;
using System.Threading.Tasks;
using Eqwww.Domain.Models.Identity;
using Microsoft.EntityFrameworkCore.Internal;

namespace Eqwww.App.SystemManage
{
    public class StrategoryApp
    {
        private ApplicationDbContext _context;
        private DatabaseLogApp _dbLogApp;
        private IModelHandler _modelHandler;
        private RoleManager<RoleModel> _roleManager;

        public StrategoryApp(ApplicationDbContext context,
            DatabaseLogApp databaseLogApp,
            IModelHandler modelHandler,
            RoleManager<RoleModel> roleManager)
        {
            _context = context;
            _dbLogApp = databaseLogApp;
            _modelHandler = modelHandler;
            _roleManager = roleManager;
        }

        /// <summary>
        /// 新建策略
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public ModelResult Create(StrategoryModel model)
        {
            if (IsExistCode(model.Code))
                return Common.ErrorResult("编码已经存在");

            _modelHandler.Create(model);
            _context.Sys_Strategorys.Add(model);
            _dbLogApp.LogCreateInformation(model.Id, model,"创建策略");
            _context.SaveChanges();
            return Common.SuccessResult();
        }

        /// <summary>
        /// 更新策略
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public ModelResult Update(StrategoryModel model)
        {
            var oldModel = Get(model.Id);
            if (oldModel == null)
                return Common.ErrorResult("未找到要更新的实体");
            if (oldModel.IsSystem == true)
                return Common.ErrorResult("系统策略不允许修改");

            if (IsExistCode(model.Code, model.Id))
                return Common.ErrorResult("编码已经存在");

            oldModel.Code = model.Code;
            oldModel.Name = model.Name;
            oldModel.SortCode = model.SortCode;
            oldModel.Description = model.Description;

            _modelHandler.Update(oldModel);
            _context.Sys_Strategorys.Update(oldModel);
            _dbLogApp.LogUpdateInformation(oldModel.Id, oldModel,"更新策略");
            _context.SaveChanges();
            return Common.SuccessResult();
        }

        /// <summary>
        /// 移除策略，保留策略关联信息
        /// </summary>
        /// <param name="strategoryId"></param>
        /// <returns></returns>
        public ModelResult Remove(string strategoryId)
        {

            var model = _context.Sys_Strategorys.FirstOrDefault(x => x.Id == strategoryId);
            if (model == null)
                return Common.ErrorResult("指定Id的策略不存在");
            if (model.IsSystem == true)
                return Common.ErrorResult("系统策略不允许移除");

            var relationRoles = GetRolesByStrategoryId(strategoryId);
            if (relationRoles.Count() > 0)
                return Common.ErrorResult("策略已关联角色，不允许移除");

            _modelHandler.Delete(model);
            _context.Sys_Strategorys.Update(model);
            _dbLogApp.LogRemoveInformation(strategoryId, model,"逻辑删除策略");
            _context.SaveChanges();
            return Common.SuccessResult();
        }

        

        public StrategoryModel Get(string id, bool containDeleted = false)
        {
            var expression = ExtLinq.True<StrategoryModel>();
            if (!containDeleted)
                expression = expression.And(x => x.DeleteMark != true);
            expression = expression.And(x => x.Id == id);
            return _context.Sys_Strategorys.AsNoTracking().FirstOrDefault(expression);
        }

        /// <summary>
        /// 根据策略id更新策略-角色信息
        /// </summary>
        /// <param name="strategoryId"></param>
        /// <param name="roles"></param>
        /// <returns></returns>
        public ModelResult UpdateRelatedRolesByStrategoryId(string strategoryId, string[] roles)
        {
            var model = _context.Sys_Strategorys.FirstOrDefault(x => x.Id == strategoryId);
            if (model == null)
                return Common.ErrorResult("指定Id的策略不存在");
            
            var removedRelatedRoles = _context.Sys_StrategoryRoles.Where(x => x.StrategoryId == strategoryId);
            if (removedRelatedRoles.Count() > 0)
                _context.RemoveRange(removedRelatedRoles);

            var relatedRoles = from p in roles
                               select new StrategoryRoleModel
                               {
                                   Id = Guid.NewGuid().ToString(),
                                   StrategoryId = strategoryId,
                                   RoleId = p
                               };
            _context.AddRange(relatedRoles);
            _context.SaveChanges();
            var objectIds = String.Join(',', (from p in relatedRoles select p.Id));
            _dbLogApp.LogUpdateInformation(objectIds, relatedRoles, "更新策略关联的角色列表");
            return Common.SuccessResult();
        }

        /// <summary>
        /// 根据角色id更新策略-角色信息
        /// </summary>
        /// <param name="roleId"></param>
        /// <param name="strategorys"></param>
        /// <returns></returns>
        public ModelResult UpdateRelatedRolesByRoleId(string roleId, string[] strategorys)
        {
            var role = _roleManager.FindByIdAsync(roleId).Result;
            if (role == null)
                return Common.ErrorResult("指定id的角色不存在");


            var removedRelatedRoles = _context.Sys_StrategoryRoles.Where(x => x.RoleId == roleId);
            _context.RemoveRange(removedRelatedRoles);
            var relatedRoles = from p in _context.Sys_Strategorys.Where(x => x.DeleteMark != true && strategorys.Contains(x.Id))
                               select new StrategoryRoleModel
                               {
                                   Id=Guid.NewGuid().ToString(),
                                   StrategoryId = p.Id,
                                   RoleId = roleId
                               };

            _context.AddRange(relatedRoles);
            _context.SaveChanges();
            var objectIds = String.Join(',', (from p in relatedRoles select p.Id));
            _dbLogApp.LogUpdateInformation(objectIds, relatedRoles, "更新角色关联的策略列表");
            return Common.SuccessResult();
        }

        /// <summary>
        /// 更新策略-模块信息和策略-按钮信息
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public ModelResult UpdatePermissions(string strategoryId, string[] permissions)
        {
            var model = _context.Sys_Strategorys.AsNoTracking().FirstOrDefault(x => x.Id == strategoryId);
            if (model == null)
                return Common.ErrorResult("未找到指定Id的策略");

            if (model.IsSuper == true)
                return Common.ErrorResult("超管策略拥有全部模块和按钮权限,不允许修改");

            var modules = from p in _context.Sys_Modules.AsNoTracking().Where(x =>x.DeleteMark!=true&& permissions.Contains(x.Id))
                          select new StrategoryModuleModel
                          {
                              Id=Guid.NewGuid().ToString(),
                              StrategoryId = strategoryId,
                              ModuleId = p.Id
                          };
            var buttons = from p in _context.Sys_ModuleButtons.AsNoTracking().Where(x =>x.DeleteMark!=true&& permissions.Contains(x.Id))
                          select new StrategoryModuleButtonModel
                          {
                              Id = Guid.NewGuid().ToString(),
                              StrategoryId = strategoryId,
                              ModuleButtonId = p.Id
                          };

            var moduleClaims = from p in _context.Sys_ModuleClaims.AsNoTracking().Where(x => x.DeleteMark != true && permissions.Contains(x.Id))
                               select new StrategoryModuleClaimModel
                               {
                                   Id = Guid.NewGuid().ToString(),
                                   StrategoryId = strategoryId,
                                   ClaimId = p.Id
                               };
            var buttonClaims = from p in _context.Sys_ModuleButtonClaims.AsNoTracking().Where(x => x.DeleteMark != true && permissions.Contains(x.Id))
                               select new StrategoryModuleButtonClaimModel
                               {
                                   Id = Guid.NewGuid().ToString(),
                                   StrategoryId = strategoryId,
                                   ClaimId = p.Id
                               };

            var removedModules = _context.Sys_StrategoryModules.AsNoTracking().Where(x => x.StrategoryId == strategoryId);
            _context.Sys_StrategoryModules.RemoveRange(removedModules);

            var removedButtons = _context.Sys_StrategoryModuleButtons.AsNoTracking().Where(x => x.StrategoryId == strategoryId);
            _context.Sys_StrategoryModuleButtons.RemoveRange(removedButtons);

            var removeModuleClaims = _context.Sys_StrategoryModuleClaims.AsNoTracking().Where(x => x.StrategoryId == strategoryId);
            _context.Sys_StrategoryModuleClaims.RemoveRange(removeModuleClaims);

            var removeButtonClaims = _context.Sys_StrategoryModuleButtonClaims.AsNoTracking().Where(x => x.StrategoryId == strategoryId);
            _context.Sys_StrategoryModuleButtonClaims.RemoveRange(removeButtonClaims);

            _context.Sys_StrategoryModules.AddRange(modules);
            _context.Sys_StrategoryModuleButtons.AddRange(buttons);
            _context.Sys_StrategoryModuleClaims.AddRange(moduleClaims);
            _context.Sys_StrategoryModuleButtonClaims.AddRange(buttonClaims);
            _dbLogApp.LogDeleteInformation(strategoryId, removedModules, "移除策略关联的模块列表");
            _dbLogApp.LogDeleteInformation(strategoryId, removedButtons, "移除策略关联的按钮列表");
            _dbLogApp.LogDeleteInformation(strategoryId, removeModuleClaims, "移除策略关联的模块声明列表");
            _dbLogApp.LogDeleteInformation(strategoryId, removeButtonClaims, "移除策略关联的按钮声明列表");
            _dbLogApp.LogCreateInformation(strategoryId, modules, "创建策略关联的模块列表");
            _dbLogApp.LogCreateInformation(strategoryId, buttons, "创建策略关联的按钮列表");
            _dbLogApp.LogCreateInformation(strategoryId, moduleClaims, "创建策略关联的模块声明列表");
            _dbLogApp.LogCreateInformation(strategoryId, buttonClaims, "创建策略关联的按钮声明列表");
            _context.SaveChanges();
            return Common.SuccessResult();
        }

        /// <summary>
        /// 检查指定code是否存在
        /// </summary>
        /// <param name="code"></param>
        /// <returns></returns>
        public bool IsExistCode(string code)
        {
            return _context.Sys_Strategorys.Any(x => x.Code.ToLower() == code.ToLower());
        }

        /// <summary>
        /// 检查指定code是否存在
        /// </summary>
        /// <param name="code"></param>
        /// <param name="strategoryId"></param>
        /// <returns></returns>
        public bool IsExistCode(string code, string strategoryId)
        {
            return _context.Sys_Strategorys.Any(x => x.Code.ToLower() == code.ToLower() && x.Id != strategoryId);
        }

        /// <summary>
        /// 获取包含指定模块的策略列表
        /// </summary>
        /// <param name="moduleId"></param>
        /// <param name="containDeleted"></param>
        /// <returns></returns>
        public IEnumerable<StrategoryModel> GetRelatedStrategoryListByModuleId(string moduleId,bool containDeleted=false)
        {
            var strategoryIds = from p in _context.Sys_StrategoryModules.AsNoTracking().Where(x => x.ModuleId == moduleId) select p.StrategoryId;
            var strategorys = _context.Sys_Strategorys.AsNoTracking();
            if (containDeleted == false)
                strategorys = strategorys.Where(x => x.DeleteMark != true);
            return strategorys.Where(x => strategoryIds.Contains(x.Id) || x.IsSuper == true).OrderBy(x => x.SortCode);
        }

        /// <summary>
        /// 获取包含指定按钮的策略列表
        /// </summary>
        /// <param name="buttonId"></param>
        /// <param name="containDeleted"></param>
        /// <returns></returns>
        public IEnumerable<StrategoryModel> GetRelatedStrategoryListByButtonId(string buttonId, bool containDeleted = false)
        {
            var strategoryIds = from p in _context.Sys_StrategoryModuleButtons.AsNoTracking().Where(x => x.ModuleButtonId == buttonId) select p.StrategoryId;
            var strategorys = _context.Sys_Strategorys.AsNoTracking();
            if (containDeleted == false)
                strategorys = strategorys.Where(x => x.DeleteMark != true);
            return strategorys.Where(x => strategoryIds.Contains(x.Id) || x.IsSuper == true).OrderBy(x => x.SortCode);
        }

        /// <summary>
        /// 根据角色Id获取所有
        /// </summary>
        /// <param name="roleId"></param>
        /// <returns></returns>
        public List<ListToggleModel> GetAllStrategorysByRoleId(string roleId)
        {
            var strategoryIds = from p in _context.Sys_StrategoryRoles.Where(x => x.RoleId == roleId)
                                select p.StrategoryId;

            var data = from p in _context.Sys_Strategorys.AsNoTracking().Where(x => x.DeleteMark != true).OrderBy(x => x.SortCode)
                       select new ListToggleModel
                       {
                           Checked = strategoryIds.Contains(p.Id),
                           Disabled = false,
                           Title = p.Name,
                           Description = p.Description,
                           SortCode = p.SortCode,
                           Value = p.Id
                       };
            return data.ToList();
        }

        /// <summary>
        /// 获取指定策略的关联角色列表
        /// </summary>
        /// <param name="strategoryId"></param>
        /// <returns></returns>
        public IEnumerable<RoleModel> GetRolesByStrategoryId(string strategoryId)
        {
            var roleIds =from p in _context.Sys_StrategoryRoles.AsNoTracking().Where(x => x.StrategoryId == strategoryId) select p.RoleId;
            var roles = _roleManager.Roles.Where(x => roleIds.Contains(x.Id) && x.DeleteMark != true).OrderBy(x => x.SortCode);
            return roles;
        }

        /// <summary>
        /// 获取指定角色的关联策略列表
        /// </summary>
        /// <param name="roleId"></param>
        /// <returns></returns>
        public IEnumerable<StrategoryModel> GetStrategorysByRoleId(string roleId)
        {
            var strategoryIds = from p in _context.Sys_StrategoryRoles.AsNoTracking().Where(x => x.RoleId == roleId) select p.StrategoryId;
            var data = _context.Sys_Strategorys.Where(x => strategoryIds.Contains(x.Id) && x.DeleteMark != true).OrderBy(x => x.SortCode);
            return data.ToList();
        }

        public IList<StrategoryModel> GetPagedList(string keyword, Pagination pagination)
        {
            var exp = ExtLinq.True<StrategoryModel>();
            exp = exp.And(x => x.DeleteMark != true);
            if (!string.IsNullOrEmpty(keyword))
                exp = exp.And(x => x.Name.Contains(keyword));
            var data = _context.FindList(exp, pagination);
            return data;
        }

        public ModelResult UpdateIsSystem(string id, bool issystem)
        {
            var model = _context.Set<StrategoryModel>().FirstOrDefault(x => x.Id == id);
            if (model == null)
                return Common.ErrorResult("未找到指定id的实体");

            model.IsSystem = issystem;
            _dbLogApp.LogUpdateInformation(id, model,"更新策略【系统】标识"+issystem.ToString());
            _context.SaveChanges();

            return Common.SuccessResult();
        }
    }
}
